<?php
/**
 * Svick a Fast Simple Smart PHP FrameWork
 * Author: Tommy 863758705@qq.com
 * Link: http://svick.tomener.com/
 * Since: 2022
 */

namespace lib\wechat;

use Exception;
use lib\lock\FileLockLib;
use Svick\Cache\Cache;
use Svick\Config\Config;
use Svick\Http\Client\Http;
use Svick\Log\Log;

class AccessToken
{
    /**
     * @var array 微信appid secret
     */
    private static array $key = [];

    public static function init()
    {
        if (empty(self::$key) ) {
            self::$key = Config::runtime('wechat');
        }
    }

    /**
     * 获取公众号accessToken
     *
     * @throws Exception
     */
    public static function mp($force = false)
    {
        self::init();
        return self::getAccessTokenByCache('mp', $force);
    }

    /**
     * 获取小程序accessToken
     *
     * @throws Exception
     */
    public static function ma($force = false)
    {
        self::init();
        return self::getAccessTokenByCache('ma', $force);
    }

    /**
     * 从缓存获取accessToken（防止高并发）
     *
     * @param string $name mp ma
     * @param bool $force
     * @return bool|string
     * @throws Exception
     */
    private static function getAccessTokenByCache($name, $force = false)
    {
        $cache_key = $name . 'AccessToken';
        $access_token = Cache::get($cache_key);
        if (!$force && $access_token) {
            return $access_token;
        }

        $lock = new FileLockLib($cache_key);
        if ($lock->lock()) {
            $ret = self::getAccessToken($name);
            $access_token = $ret['access_token'];
            Cache::set($cache_key, $access_token, 1200);
            $lock->unlock();
        } else {
            for ($i = 0; $i < 10; $i++) {
                usleep(300000);
                $access_token = Cache::get($cache_key);
                if ($access_token) {
                    return $access_token;
                }
            }
        }
        return $access_token;
    }

    /**
     * @throws Exception
     */
    public static function getAccessToken($name)
    {
        $api_url = sprintf('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s', self::$key[$name]['appid'], self::$key[$name]['secret']);
        $res = Http::get($api_url);
        if ($res->status() != 200) {
            throw new Exception('get access token error');
        }
        $ret = $res->array();
        if (isset($ret['errcode']) || !isset($ret['access_token'])) {
            Log::single(['errcode' => $ret['errcode'], 'errmsg' => $ret['errmsg']], 'get_access_token.err');
            throw new Exception('get access token error');
        }

        return $ret;
    }
}
